In [1]:
import sys
sys.path.append(r'AutomaticDifferentiation\build\Release')
import automatic_differentiation as ad
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML
Automatic Differentiation Example¶
$f(x) = 3x^2+5x-10$
$f'(x) = 6x+5$
Evaluating both of these expressions at $x = 3$:
$f(3) = 32$
$f'(3) = 23$
Getting the same result with the automatic_differentiation module:
In [2]:
def function(x):
dn = ad.DualNumber(x, 1) # derivative of x is 1
return 3 * dn ** 2 + 5 * dn - 10
ans = function(3)
print(f"f(3) = {ans.get_x()}, f'(3) = {ans.get_dx()}")
f(3) = 32.0, f'(3) = 23.0
Visualsing Functions and Derivatives¶
In [3]:
def display_function_and_derivative(func, x_start, x_end, title_string='Function and its Derivative'):
# Create the figure and axis
fig, ax = plt.subplots(figsize=(10, 6))
plt.close() # Prevents displaying the static figure
# Set the x range for our function
x_range = np.linspace(x_start, x_end, 100)
# Calculate function values for the full curve
y_values = np.array([func(x).get_x() for x in x_range])
# Plot the main function curve
ax.plot(x_range, y_values, 'b-', lw=2, label='f(x)')
# Point that will move along the curve
point, = ax.plot([], [], 'ro', ms=5)
# Tangent line that will update
tangent_line, = ax.plot([], [], 'r-', lw=1, label='Tangent')
# Text to display the derivative value
derivative_text = ax.text(0.02, 0.95, '', transform=ax.transAxes)
# Set up the axes
ax.set_xlim(x_start, x_end)
ylim_margin = (max(y_values) - min(y_values)) / 20
ax.set_ylim(min(y_values) - ylim_margin, max(y_values) + ylim_margin)
ax.set_xlabel('x', fontsize=14)
ax.set_ylabel('f(x)', fontsize=14)
ax.set_title(title_string, fontsize=16)
ax.grid(True)
ax.legend(loc='lower right')
# Number of frames in the animation
frames = 100
# Points along the curve to evaluate
animation_x_values = np.linspace(x_start, x_end, frames)
# Update function for the animation
def update(frame):
# Current x value
x = animation_x_values[frame]
# Get function value and derivative
dual_number = func(x)
f_x = dual_number.get_x()
df_x = dual_number.get_dx()
# Update the point position
point.set_data([x], [f_x])
# Create tangent line
# The tangent line is represented by: y = f'(x)*(x-x0) + f(x0)
tangent_x = np.array([x_start, x_end])
tangent_y = df_x * (tangent_x - x) + f_x
tangent_line.set_data(tangent_x, tangent_y)
# Update derivative text
derivative_text.set_text(f"f'(x) = {df_x:.3f}")
return point, tangent_line, derivative_text
# Create the animation
animation = FuncAnimation(fig, update, frames=frames, interval=50, blit=True)
return animation
In [4]:
def function(x):
dn = ad.DualNumber(x, 1)
return dn ** 3 + 50 * dn ** 2 - 3 * dn + 18
HTML(display_function_and_derivative(function, -80, 60, '$f(x) = x^3 + 50x^2 - 3x + 18$').to_jshtml())
Out[4]:
In [5]:
def function(x):
dn = ad.DualNumber(x, 1)
return dn ** 2 - 5 * dn + 6 - 5 * dn ** 3 - 5 * np.e ** (-50 * dn ** 2)
HTML(display_function_and_derivative(function, -0.5, 0.5, '$f(x) = x^2 - 5x + 6 - 5x^3 - 5e^{-50x^2}$').to_jshtml())
Out[5]:
In [6]:
def function(x):
dn = ad.DualNumber(x, 1)
return np.e ** (-0.1 * dn) * (dn * 5).sin()
HTML(display_function_and_derivative(function, 0, 4, '$e^{-0.1x}sin(5x)$').to_jshtml())
Out[6]:
In [7]:
def function(x):
dn = ad.DualNumber(x, 1)
return (dn.sin()).tan() - (3 * dn).cos()
HTML(display_function_and_derivative(function, -3, 5, '$tan(sin(x)) - cos(3x)$').to_jshtml())
Out[7]: